from django.contrib.gis.db import models
from django.contrib.gis.gdal.envelope import Envelope
from django.contrib.gis.geos.collections import GeometryCollection
from django.contrib.gis.models import SpatialRefSys
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from dataset import DataSource, DataType, DataFormat
from layers import Layer, LayerStyle
from location import Location
from meta import Agent, Organization, Keyword

class WebMapService(models.Model):
	__module__ = 'duetopia.register.models'
	source = models.ForeignKey(DataSource, verbose_name=_('data source'))
	version = models.CharField(max_length=8, default='1.1.1', verbose_name=_('version'))
	formats = models.ManyToManyField(DataFormat, verbose_name=_('formats'))
	class Meta:
		verbose_name = _('Web Map Service')
		verbose_name_plural = _('Web Map Services')
	class Admin:
		list_display = ("source", "version")
		search_fields = ("source__uri",)
	@property
	def wms(self):
		"""return the wms object given by owslib. internal use"""
		from owslib import wms
		if not hasattr(self, '_wms'):
			self._wms = wms.WebMapService(self.source.uri, self.version)
		return self._wms
	@property
	def title(self):
		"""return the reported title of this data source"""
		return self.wms.capabilities.title

	@property
	def keywords(self):
		"""
		return a list of keyword,language tuples associated
		with this data source
		"""
		return map(lambda x: (x, 'en'), self.wms.capabilities.keywords)
		
	@property
	def abstract(self):
		"""return the reported abstract for this data source"""
		return self.wms.capabilities.abstract
	def _get_formats(self):
		"""
		query and save the image formats supported by this WMS server.
		return the "preferred" (arbitrary) format for requesting rendered
		images. the return value is used for making thumbnails. internal
		use.
		"""
		## query formats from WMS server
		formats = self.wms.capabilities.getOperationByName('GetMap').formatOptions
		for mimetype in formats:
			try:
				format = DataFormat.objects.get(mimetype=mimetype)
				if not self.formats.filter(id=format.id):
					self.formats.add(format)
			except DataFormat.DoesNotExist:
				pass
		## find a preferred format to return
		format = None
		for mimetype in ('image/png', 'image/jpeg', 'image/gif'):
			if self.formats.filter(mimetype=mimetype):
				format = self.formats.get(mimetype=mimetype)
				break
		return format

	def get_contacts(self):
		"""
		called by DataSource's synchronization routines.
		"""
		if self.wms.capabilities.provider is not None:
			cw = {}
			for attr in ('address', 'city', 'region', 'country', 'postcode'):
				val = getattr(self.wms.capabilities.provider, attr)
				if val: cw[attr] = val
			if cw: location, created = Location.objects.get_or_create(**cw)
			else: location = None

			if self.wms.capabilities.provider.organization:
				cw = {'name': self.wms.capabilities.provider.organization}
				if location: cw['location'] = location
				org, created = Organization.objects.get_or_create(**cw)
			else: org = None

			cw = {
				'name': self.wms.capabilities.provider.name,
				'email': self.wms.capabilities.provider.email,
				'organization': org,
				'position': self.wms.capabilities.provider.position,
				'location': location,
			}
			if cw["name"] and cw["email"]:
                		agent, created = Agent.objects.get_or_create(**cw)
       				if not self.source.dataset.contacts.filter(id = agent.id):
	       				self.source.dataset.contacts.add(agent)

	@property
	def extents(self):
		dataset = self.source.dataset
		extents = [x.extents for x in dataset.layer_set.all() if x.extents is not None]
		if extents:
			return GeometryCollection(extents).envelope
        
	def get_layers(self):
		"""
		called by DataSource's synchronization routines. query a list
		of available layers and save them along with associated metadata
		in the database. also make thumbnails if possible.
		"""
		img_format = self._get_formats()
		for l in self.wms.capabilities.contents:
			if not l.name:
				### kludge: we see this from atlas.gc.ca to
				### make data sets appear as container layers
				### for now just skip the container and consider
				### as one big dataset
				continue
			### populate core data
			try:
				layer = Layer.objects.get(dataset=self.source.dataset, name=l.name)
			except Layer.DoesNotExist:
				layer = Layer(dataset=self.source.dataset, name=l.name)
				## gotta be a better way than hard coding it...
				## that said, WMS are by definition raster... i think...
				layer.dataType = DataType.objects.get(name = 'Raster')
			layer.title = l.title
			layer.extents = Envelope(*l.boundingBoxWGS84).wkt
			if img_format:
				layer.thumbnail_format = img_format
			layer.save()
			### populate available SRIDs
			for srid in l.crsOptions:
				if not srid:
					continue
				auth_name, auth_srid = srid.split(':', 1)
				try:
					srs = SpatialRefSys.objects.get(auth_name=auth_name,
									auth_srid=auth_srid)
					if layer.srs.filter(srid = srs.srid).count() == 0:
						layer.srs.add(srs)
				except SpatialRefSys.DoesNotExist:
					pass
			if not layer.srs: ### fill in a default SRS if necessary
				srs = SpatialRefSys.objects.get(srid = 4326)
				layer.srs.add(srs)

			### populate available styles
			for name in l.styles:
				if 'title' in l.styles[name]:
					title = l.styles[name]['title']
				else:
					title = '%s style' % (name,)
				if not layer.style_set.filter(name=name):
					style, created = LayerStyle.objects.get_or_create(layer=layer, name=name, title=title)

			### populate keywords if available
			if hasattr(l, 'keywords'):
				for k in l.keywords:
					keyword, c = Keyword.objects.get_or_create(word=k, lang='en')
					if not layer.keywords.filter(id=keyword.id):
						layer.keywords.add(keyword)

			if img_format:
				self._get_thumbnail(layer, srid, l.boundingBoxWGS84)

	def _get_thumbnail(self, layer, srid, box):
		return
		try:
			filename = layer.thumbnail_file
		except ValueError:
			return
		print "thumbnail", filename
		img = self.wms.getmap(
			layers = [layer.name],
			srs = srid,
			bbox = box,
			size = (100, 75),
			format = layer.thumbnail_format.mimetype,
		)
		fp = open(filename, 'wb')
		fp.write(img.read())
		fp.close()
		print "thumbnail done"
